import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConcurrentLinkedList<T> {

    class ListNode {
        T data;
        ListNode next;
    }

    private ListNode head;
    private ListNode tail;
    private Lock lock;

    public ConcurrentLinkedList() {
        ListNode dummy = new ListNode();
        lock = new ReentrantLock(false);
        head = dummy;
        tail = dummy;
    }

    public synchronized void offer(T data) {
        ListNode newNode = new ListNode();
        newNode.data = data;
        // lock.lock();
        tail.next = newNode;
        tail = newNode;
        // lock.unlock();
    }

    public synchronized T poll() {
        // lock.lock();
        if (head.next == null) {
            // lock.unlock();
            return null;
        }
        T val = head.next.data;
        head = head.next;
        // lock.unlock();
        return val;
    }

    void debug() {
        ListNode cur = head.next;
        while (cur != null) {
            System.out.println(cur.data);
            cur = cur.next;
        }
    }

    public static void main(String[] args) {
        ConcurrentLinkedList<Integer> list = new ConcurrentLinkedList<Integer>();
        list.offer(10);
        list.offer(11);
        list.offer(12);
        System.out.println("poll: " + list.poll());
        System.out.println("poll: " + list.poll());
        System.out.println("poll: " + list.poll());
        System.out.println("poll: " + list.poll());
        list.offer(10);
        list.offer(11);
        list.offer(12);
        list.debug();
    }

}
